package control

import (
	"hi-jvm/instructions/base"
	"hi-jvm/instructions/util"
	"hi-jvm/rtda"
)

/*
Java语言中，switch-case有两种实现方式：
1： 如果case值可以编码成一个索引表，则实现成tableswitch指令
2： 否则，实现成lookupswitch指令
 */


/*
tableswitch
<0-3 byte pad>
defaultbyte1
defaultbyte2
defaultbyte3
defaultbyte4
lowbyte1
lowbyte2
lowbyte3
lowbyte4
highbyte1
highbyte2
highbyte3
highbyte4
jump offsets...
*/
// Access jump table by index and jump
// tableswitch指令码的后面有0-3个字节的padding，以保证defaultOffset在字节码中的地址是4的倍数
type TABLE_SWITCH struct {
	defaultOffset int32		// 对应默认情况下执行跳转所需的字节码偏移量
	low           int32		// 记录case的取值范围
	high          int32
	jumpOffsets   []int32	// 存放high - low + 1个int值， 对应各种case情况下，执行跳转所需的字节码偏移量
}

/*
tableswitch指令码的后面有0-3个字节的padding，以保证defaultOffset在字节码中的地址是4的倍数
defaultOffset对应默认情况下执行跳转所需的字节码偏移量
 */
func (self *TABLE_SWITCH) FetchOperands(reader *util.BytecodeReader) {
	reader.SkipPadding()
	self.defaultOffset = reader.ReadInt32()
	self.low = reader.ReadInt32()
	self.high = reader.ReadInt32()
	jumpOffsetsCount := self.high - self.low + 1
	self.jumpOffsets = reader.ReadInt32s(jumpOffsetsCount)
}

/*
先从操作数栈中弹出一个int变量
看它是否在low和hight给定的范围之内
	如果在，则从jumpOffsets表中查出偏移量进行跳转
	否则，按照defaultOffset跳转
 */
func (self *TABLE_SWITCH) Execute(frame *rtda.Frame) {
	index := frame.OperandStack.PopInt()

	var offset int
	if index >= self.low && index <= self.high {
		offset = int(self.jumpOffsets[index-self.low])
	} else {
		offset = int(self.defaultOffset)
	}

	base.Branch(frame, offset)
}
